using AngleSharp;
using AngleSharp.Dom;
using Crux.Core.LangChain.Abstractions.DocumentLoaders;

namespace Crux.Core.LangChain.DocumentLoaders.Web;
/// <summary>
/// 
/// </summary>
public class WebLoader : IDocumentLoader
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="dataSource"></param>
    /// <param name="settings"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    /// <exception cref="NotImplementedException"></exception>
    public async Task<IReadOnlyCollection<Abstractions.DocumentLoaders.Document>> LoadAsync(
        DataSource dataSource,
        DocumentLoaderSettings? settings = null,
        CancellationToken cancellationToken = default)
    {
        dataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource));

        var config = Configuration.Default.WithDefaultLoader();

        using var context = BrowsingContext.New(config);

        using var document = await GetDocument(context, dataSource, cancellationToken).ConfigureAwait(false);

        foreach (var element in document.QuerySelectorAll("script, style, meta, link"))
        {
            element.Remove();
        }

        var html = document.QuerySelector("html") ??
            throw new NotSupportedException("Not supported for pages without <html> tag");

        var metadata = settings.CollectMetadataIfRequired(dataSource);

        return [new Abstractions.DocumentLoaders.Document(html.TextContent, metadata: metadata)];
    }
    private async Task<IDocument> GetDocument(IBrowsingContext context, DataSource dataSource, CancellationToken cancellationToken = default)
    {
        switch (dataSource.Type)
        {
            case DataSourceType.Uri:
                return await context.OpenAsync(dataSource.Value!, cancellation: cancellationToken).ConfigureAwait(false);

            case DataSourceType.Stream:
                {
                    using var stream = await dataSource.GetStreamAsync(cancellationToken).ConfigureAwait(false);

                    using var reader = new StreamReader(stream, detectEncodingFromByteOrderMarks: true);

                    string content = await reader.ReadToEndAsync().ConfigureAwait(false);

                    return await context.OpenAsync(req => req.Content(content)).ConfigureAwait(false);
                };
            default:
                throw new NotSupportedException("Not supported for pages without <html> tag");
        }


    }
}